package com.ciwong.mobilelib.widget.switchbutton;

/**
 * TODO Description of class。
 * <p/>
 * TODO Detail Description
 * <p/>
 * TODO Sample Code
 * <pre>
 * </pre>
 *
 * @author res-qqlin
 * @version ciwong v.2.0 2015/8/5
 * @since ciwong v.2.0
 */
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.CompoundButton;

import com.ciwong.mobilelib.R;
import com.ciwong.mobilelib.ui.BaseActivity;

/**
 * SwitchButton widget which is easy to use
 */

public class SwitchButton extends CompoundButton
{
    private boolean canMove = true;

    private boolean mIsChecked = false;

    /**
     * zone for thumb to move inside
     */
    private Rect mSafeZone;

    /**
     * zone for background
     */
    private Rect mBackZone;

    private Rect mThumbZone;

    private AnimationController mAnimationController;

    private SBAnimationListener mOnAnimateListener = new SBAnimationListener();

    private boolean isAnimating = false;

    private float mStartX, mStartY, mLastX;

    private float mCenterPos;

    private int mTouchSlop;

    private int mClickTimeout;

    private OnCheckedChangeListener mOnCheckedChangeListener;

    private int thumbWidth;

    private Drawable thumbDrawable;

    private Drawable onDrawable;

    private Drawable offDrawable;

    // 动画的速率
    private int velocity = 8;

    // 密度
    private float density;

    private Context mctx;

    public SwitchButton(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        this.mctx = context;
        density = context.getResources().getDisplayMetrics().density;
        initView();
    }

    public SwitchButton(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public SwitchButton(Context context)
    {
        this(context, null);
    }

    private void initView()
    {
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        mClickTimeout = ViewConfiguration.getPressedStateDuration()
                + ViewConfiguration.getTapTimeout();
        mAnimationController = AnimationController.getDefault().init(
                mOnAnimateListener);
        mAnimationController.setVelocity(velocity);

        thumbDrawable = getResources().getDrawable(R.mipmap.ios_thumb);
        offDrawable = getResources().getDrawable(R.drawable.ios_off);

        onDrawable = new GradientDrawable();
        ((GradientDrawable) onDrawable).setCornerRadius(999);
        ((GradientDrawable) onDrawable).setColor(Color.parseColor("#43d95d"));

        Bitmap thumbBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ios_thumb);
        thumbWidth = thumbBitmap.getWidth();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        setMeasuredDimension(
                (int) (thumbWidth * 1.5 + getPaddingLeft() + getPaddingRight()),
                thumbWidth + getPaddingTop() + getPaddingBottom());
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        setup();
    }

    private void setup()
    {
        int w = getMeasuredWidth();
        int h = getMeasuredHeight();
        setupBackZone(w, h);
        setupSafeZone(w, h);
        setupThumbZone(w, h);

        onDrawable.setBounds(mBackZone);
        offDrawable.setBounds(mBackZone);
        thumbDrawable.setBounds(mThumbZone);
    }

    /**
     * setup zone for thumb to move
     *
     * @param w
     * @param h
     */
    private void setupSafeZone(int w, int h)
    {
        if (mSafeZone == null)
        {
            mSafeZone = new Rect();
        }
        int left, right, top, bottom;
        left = getPaddingLeft();
        right = w - getPaddingRight();
        top = getPaddingTop();
        bottom = h - getPaddingBottom();
        mSafeZone.set(left, top, right, bottom);

        mCenterPos = (mSafeZone.left + mSafeZone.right - thumbWidth) / 2;

    }

    private void setupBackZone(int w, int h)
    {
        if (mBackZone == null)
        {
            mBackZone = new Rect();
        }
        int left, right, top, bottom;
        left = getPaddingLeft() + (int) (5 * density);
        right = w - getPaddingRight() - (int) (5 * density);
        top = getPaddingTop() + (int) (2.5 * density);
        bottom = h - getPaddingBottom() - (int) (8 * density);
        mBackZone.set(left, top, right, bottom);
    }

    private void setupThumbZone(int w, int h)
    {
        if (mThumbZone == null)
        {
            mThumbZone = new Rect();
        }
        int left, right, top, bottom;
        left = mIsChecked ? (mSafeZone.right - thumbWidth) : mSafeZone.left;
        right = left + thumbWidth;
        top = mSafeZone.top;
        bottom = top + thumbWidth;
        mThumbZone.set(left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        offDrawable.draw(canvas);
        onDrawable.setAlpha(calcAlpha());
        onDrawable.draw(canvas);
        thumbDrawable.draw(canvas);
    }

    /**
     * 计算透明度值
     *
     * @return 0 ~ 255
     */
    private int calcAlpha()
    {
        int alpha = 255;
        if (mSafeZone != null && mSafeZone.right != mSafeZone.left)
        {
            int backWidth = mSafeZone.right - thumbWidth - mSafeZone.left;
            if (backWidth > 0)
            {
                alpha = (mThumbZone.left - mSafeZone.left) * 255 / backWidth;
            }
        }
        return alpha;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {

        if (isAnimating || !isEnabled())
        {
            return false;
        }
        float deltaX = event.getX() - mStartX;
        float deltaY = event.getY() - mStartY;

        // status the view going to change to when finger released
        boolean nextStatus = mIsChecked;

        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
//                ((BaseActivity) mctx).setActivityCanMoveHandler(this);
                mStartX = event.getX();
                mStartY = event.getY();
                mLastX = mStartX;
                setPressed(true);
                break;

            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                moveThumb((int) (x - mLastX));
                mLastX = x;
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                setPressed(false);
                // 用Thump的左边坐标和重点左边比较，判断是否选中
                nextStatus = mThumbZone.left > mCenterPos;
                float time = event.getEventTime() - event.getDownTime();
                if (deltaX < mTouchSlop && deltaY < mTouchSlop
                        && time < mClickTimeout)
                {
                    // 代码主动去调用控件的点击事件（模拟人手去触摸控件）
                    performClick();
                }
                else
                {
                    slideToChecked(nextStatus);
                }
                break;

            default:
                break;
        }
        invalidate();
        return true;
    }

    @Override
    public void setChecked(final boolean checked)
    {
        if (mThumbZone != null)
        {
            moveThumb(checked ? getMeasuredWidth() : -getMeasuredWidth());
        }
        setCheckedInClass(checked);
    }

    @Override
    public boolean isChecked()
    {
        return mIsChecked;
    }

    @Override
    public void toggle()
    {
        toggle(true);
    }

    public void toggle(boolean animated)
    {
        if (animated)
        {
            slideToChecked(!mIsChecked);
        }
        else
        {
            setChecked(!mIsChecked);
        }
    }

    @Override
    protected void drawableStateChanged()
    {
        super.drawableStateChanged();
        setDrawableState(thumbDrawable);
        setDrawableState(onDrawable);
        setDrawableState(offDrawable);
    }

    private void setDrawableState(Drawable drawable)
    {
        if (drawable != null)
        {
            int[] myDrawableState = getDrawableState();
            drawable.setState(myDrawableState);
            invalidate();
        }
    }

    public void setOnCheckedChangeListener(
            OnCheckedChangeListener onCheckedChangeListener)
    {
        if (onCheckedChangeListener == null)
        {
            throw new IllegalArgumentException(
                    "onCheckedChangeListener can not be null");
        }
        mOnCheckedChangeListener = onCheckedChangeListener;
    }

    private void setCheckedInClass(boolean checked)
    {
        if (mIsChecked == checked)
        {
            return;
        }
        mIsChecked = checked;
        refreshDrawableState();
        if (mOnCheckedChangeListener != null)
        {
            mOnCheckedChangeListener.onCheckedChanged(this, mIsChecked);
        }
    }

    public void slideToChecked(boolean checked)
    {
        if (isAnimating)
        {
            return;
        }
        int from = mThumbZone.left;
        int to = checked ? mSafeZone.right - thumbWidth : mSafeZone.left;
        mAnimationController.startAnimation(from, to);
    }

    private void moveThumb(int delta)
    {
        int newLeft = mThumbZone.left + delta;
        int newRight = mThumbZone.right + delta;
        if (newLeft < mSafeZone.left)
        {
            newLeft = mSafeZone.left;
            newRight = newLeft + thumbWidth;
        }
        if (newRight > mSafeZone.right)
        {
            newRight = mSafeZone.right;
            newLeft = newRight - thumbWidth;
        }
        // 移动 Thumb
        mThumbZone.set(newLeft, mThumbZone.top, newRight, mThumbZone.bottom);
        thumbDrawable.setBounds(mThumbZone);
    }

    class SBAnimationListener implements AnimationController.OnAnimateListener
    {

        @Override
        public void onAnimationStart()
        {
            isAnimating = true;
        }

        @Override
        public boolean continueAnimating()
        {
            return mThumbZone.right < mSafeZone.right
                    && mThumbZone.left > mSafeZone.left;
        }

        @Override
        public void onFrameUpdate(int frame)
        {
            moveThumb(frame);
            postInvalidate();
        }

        @Override
        public void onAnimateComplete()
        {
            setCheckedInClass(mThumbZone.left > mCenterPos);
            isAnimating = false;
        }
    }

//    @Override
//    public boolean dispatchTouchEvent(MotionEvent event)
//    {
//        try
//        {
//            switch (event.getAction())
//            {
//                case MotionEvent.ACTION_DOWN:
////                    setCanMove(false);
//                    break;
//                case MotionEvent.ACTION_UP:
////                    setCanMove(true);
//                    break;
//                default:
//                    break;
//            }
//            return super.dispatchTouchEvent(event);
//        }
//        catch (Exception e)
//        {
//            return false;
//        }
//    }
//
//    public void setCanMove(boolean canMove)
//    {
//        this.canMove = canMove;
//        canMove();
//    }
//
//    @Override
//    public boolean canMove()
//    {
//        return canMove;
//    }
}